package com.sh.data.engine.domain.api.util;

import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.*;
import com.sh.data.engine.domain.api.model.domain.DataApiCallRecordDomain;
import com.sh.data.engine.domain.api.model.domain.rest.DataApiHttpServletRequestPayload;
import com.sh.data.engine.domain.api.model.param.DataApiCommonParam;
import com.sh.data.engine.domain.util.LogUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;

/**
 * @author: zigui.zdf
 * @description:
 * @date: 2020/11/16 13:30
 */
@Slf4j
public class DataApiUtil {

    private static final String HIT_NEW_LINE = "---/*HIT_NEW_LINE*/---";

    public static void writeLog(Long id, List<String> lines) {
        try {
            if (Objects.nonNull(id)) {
                LogUtil.writeDataApiLog(id, lines);
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }

    public static void writeLog(DataApiCallRecordDomain apiRecord, Long id, List<String> lines) {

        if (null != apiRecord) {
            // 目前只有测试模式才写日志
            try {
                if (null != apiRecord) {
                    LogUtil.writeDataApiLog(apiRecord.getId(), lines);
                }
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        } else {
            // 测试API
            try {
                if (Objects.nonNull(id)) {
                    LogUtil.writeDataApiTestLog(id, lines);
                }
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        }

    }

    public static void writeLog(
        DataApiCallRecordDomain apiRecord, DataApiCallRecordDomain taskRecord, List<String> lines) {
        if (null == apiRecord && null == taskRecord) {
            return;
        }

        Integer callType;

        if (null != taskRecord) {
            callType = taskRecord.getCallType();
        } else {
            callType = apiRecord.getCallType();
        }

        // 目前只有测试模式才写日志
        if (callType == 0) {
            try {
                if (null != taskRecord) {
                    LogUtil.writeDataApiLog(taskRecord.getId(), lines);
                }

                if (null != apiRecord) {
                    LogUtil.writeDataApiLog(apiRecord.getId(), lines);
                }
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        }
    }

    public static void writeResponse(Long recordId, String response) {
        try {
            LogUtil.writeDataApiReponse(recordId, response);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }

    public static DataApiHttpServletRequestPayload convertRequestToPayload(
        HttpServletRequest request) {

        Map<String, String> params = getParams(request);

        Map<String, String> headers = new LinkedHashMap<>();

        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            String headerValue = request.getHeader(headerName);
            headers.put(headerName, headerValue);
        }

        String token = "";

        String method = request.getMethod();

        String protocol = StringUtils.substringBefore(request.getProtocol(), "/");

        return new DataApiHttpServletRequestPayload(params, headers, token, method, protocol);
    }

    /**
     * 从请求中获取参数
     *
     * @param request
     * @return
     */
    public static Map<String, String> getParams(HttpServletRequest request) {
        // 1.请求参数（路径参数&表单参数）
        Map<String, String> params =
            request.getParameterMap().entrySet().stream()
                .collect(
                    Collectors.toMap(
                        entry -> entry.getKey(),
                        entry -> {
                            String[] values = entry.getValue();
                            if (ArrayUtils.isEmpty(values)) {
                                return null;
                            }
                            return values[0];
                        }));

        // 剔除空的数据
        Iterator<Entry<String, String>> iterator = params.entrySet().iterator();
        while (iterator.hasNext()) {
            Entry<String, String> next = iterator.next();
            if (StringUtils.isBlank(next.getValue())) {
                iterator.remove();
            }
        }

        // 2.请求头参数
        for (String param : DataApiCommonParam.params) {
            String header = request.getHeader(param);
            if (StringUtils.isNotBlank(header)) {
                params.put(param, header);
            }
        }

        return params;
    }

    public static List<SQLSelectItem> getSqlSelectItemsBySql(String sql, String dbType) {
        List<SQLStatement> statements = SQLUtils.parseStatements(sql, dbType);

        // 只考虑一条语句
        SQLStatement statement = statements.get(0);

        List<SQLSelectItem> items = null;

        // 只考虑查询语句
        if (statement instanceof SQLSelectStatement) {
            SQLSelectStatement sqlSelectStatement = (SQLSelectStatement) statement;

            SQLSelect select = sqlSelectStatement.getSelect();
            SQLSelectQuery sqlSelectQuery = select.getQuery();

            // 非union的查询语句
            if (sqlSelectQuery instanceof SQLSelectQueryBlock) {
                SQLSelectQueryBlock sqlSelectQueryBlock = (SQLSelectQueryBlock) sqlSelectQuery;
                // 获取字段列表
                items = sqlSelectQueryBlock.getSelectList();
            } else if (sqlSelectQuery instanceof SQLUnionQuery) {
                SQLUnionQuery sqlUnionQuery = (SQLUnionQuery) sqlSelectQuery;
                SQLSelectQueryBlock sqlSelectQueryBlock = sqlUnionQuery.getFirstQueryBlock();

                items = sqlSelectQueryBlock.getSelectList();
            }
        }

        return items;
    }

    public static List<String> parseMultiScript(String script) {
        if (StringUtils.isBlank(script)) {
            return Collections.emptyList();
        }
        String[] array = StringUtils.splitByWholeSeparator(script, HIT_NEW_LINE);
        if (array == null || array.length == 1) {
            return Arrays.asList(script);
        }
        List<String> list = new ArrayList<>();
        for (String element : array) {
            if (StringUtils.isBlank(element)) {
                continue;
            }

            list.add(StringUtils.trim(element));
        }
        return list;
    }

    public static String trimSQL(String sql) {
        sql = StringUtils.trim(sql);
        if (StringUtils.endsWith(sql, ";")) {
            sql = sql.substring(0, sql.length() - 1);
        }
        return StringUtils.trim(sql);
    }
}
